﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using LaughingDog.Managers;
using Microsoft.Xna.Framework;

namespace LaughingDog.Input
{
    /// <summary>
    /// An InputMapping class is used to abstract away the actual input device that you are checking on.
    /// </summary>
    public class InputMapping
    {
        private String mName = "";
        private List<Keys> mKeys = new List<Keys>();
        private List<MouseButtons> mMouseButtons = new List<MouseButtons>();
        private List<GamePadButtons> mGamePadButtons = new List<GamePadButtons>();
        private Boolean mEnabled = true;
        private PlayerIndex? mPlayerIndex = null;

        /// <summary>
        /// Gets the name of this InputMapping.
        /// </summary>
        public String Name { get { return mName; } }

        /// <summary>
        /// Gets or sets a value indicating whether this input mapping is enabled or disabled.
        /// </summary>
        public Boolean Enabled { get { return mEnabled; } set { mEnabled = value; } }

        /// <summary>
        /// Gets or sets the PlayerIndex associated with this mapping. Set to null to use as a global mapping.
        /// </summary>
        public PlayerIndex? PlayerIndex { get { return mPlayerIndex; } set { mPlayerIndex = value; } }

        /// <summary>
        /// Creates a new instance of an InputMapping object and adds it to the manager.
        /// </summary>
        /// <param name="name">The name of this InputMapping.</param>        
        public InputMapping(String name)
        {
            mName = name;

            InputManager.Instance.AddInputMapping(this);
        }

        /// <summary>
        /// Creates a new instance of an InputMapping object.
        /// </summary>
        /// <param name="name">The name of this InputMapping.</param>        
        /// <param name="managed">Set to true to auto add this Mapping to the InputManager.</param>        
        public InputMapping(String name, Boolean managed)
        {
            mName = name;

            if (managed)
                InputManager.Instance.AddInputMapping(this);
        } 

        /// <summary>
        /// Checks whether this the inputs associated with this mapping are pressed.
        /// </summary>
        /// <returns>True if the input is pressed, false if not.</returns>
        public Boolean InputPressed()
        {
            if (!mEnabled) // If not enabled simply return false.
                return false;

            foreach (Keys key in mKeys)                            
                if (InputManager.Instance.Keyboard.KeyPressed(key))
                    return true;           

            foreach (MouseButtons button in mMouseButtons)                            
                if (InputManager.Instance.Mouse.ButtonPressed(button))
                    return true;

            foreach (GamePad gamePad in InputManager.Instance.GamePads)            
                if (gamePad.IsConnected)                
                    if(mPlayerIndex == null || gamePad.PlayerIndex == mPlayerIndex)
                        foreach (GamePadButtons gamePadButton in mGamePadButtons)                    
                            if (gamePad.ButtonPressed(gamePadButton))
                                return true;                                                

            return false;
        }

        /// <summary>
        /// Checks whether this the inputs associated with this mapping were just pressed.
        /// </summary>
        /// <returns>True if the input was just pressed, false if not.</returns>
        public Boolean InputJustPressed()
        {
            if (!mEnabled) // If not enabled simply return false.
                return false;

            foreach (Keys key in mKeys)
                if (InputManager.Instance.Keyboard.KeyJustPressed(key))
                    return true;

            foreach (MouseButtons button in mMouseButtons)
                if (InputManager.Instance.Mouse.ButtonJustPressed(button))
                    return true;

            foreach (GamePad gamePad in InputManager.Instance.GamePads)
                if (gamePad.IsConnected)
                    foreach (GamePadButtons gamePadButton in mGamePadButtons)
                        if (gamePad.ButtonJustPressed(gamePadButton))
                            return true;  

            return false;
        }

        /// <summary>
        /// Checks whether this the inputs associated with this mapping were just released.
        /// </summary>
        /// <returns>True if the input was just released, false if not.</returns>
        public Boolean InputJustReleased()
        {
            if (!mEnabled) // If not enabled simply return false.
                return false;

            foreach (Keys key in mKeys)
                if (InputManager.Instance.Keyboard.KeyJustReleased(key))
                    return true;

            foreach (MouseButtons button in mMouseButtons)
                if (InputManager.Instance.Mouse.ButtonJustReleased(button))
                    return true;

            foreach (GamePad gamePad in InputManager.Instance.GamePads)
                if (gamePad.IsConnected)
                    foreach (GamePadButtons gamePadButton in mGamePadButtons)
                        if (gamePad.ButtonJustReleased(gamePadButton))
                            return true;  

            return false;
        }

        /// <summary>
        /// Checks whether this the inputs associated with this mapping are released.
        /// </summary>
        /// <returns>True if the input is released, false if not.</returns>
        public Boolean InputReleased()
        {
            if (!mEnabled) // If not enabled simply return false.
                return false;

            foreach (Keys key in mKeys)
                if (InputManager.Instance.Keyboard.KeyReleased(key))
                    return true;

            foreach (MouseButtons button in mMouseButtons)
                if (InputManager.Instance.Mouse.ButtonReleased(button))
                    return true;

            foreach (GamePad gamePad in InputManager.Instance.GamePads)
                if (gamePad.IsConnected)
                    foreach (GamePadButtons gamePadButton in mGamePadButtons)
                        if (gamePad.ButtonReleased(gamePadButton))
                            return true;  

            return false;
        }

        /// <summary>
        /// Adds a Keyboard Key to this mapping.
        /// </summary>
        /// <param name="keyboardKey">The key to add.</param>
        public void AddInput(Keys keyboardKey)
        {
            mKeys.Add(keyboardKey);
        }

        /// <summary>
        /// Adds a GamePad Button to this mapping.
        /// </summary>
        /// <param name="gamePadButton">The button to add.</param>
        public void AddInput(GamePadButtons gamePadButton)
        {
            mGamePadButtons.Add(gamePadButton);
        }

        /// <summary>
        /// Removes a Mouse Button to this mapping.
        /// </summary>
        /// <param name="mouseButton">The button to remove.</param>
        public void AddInput(MouseButtons mouseButton)
        {
            mMouseButtons.Add(mouseButton);
        }

        /// <summary>
        /// Removes a Keyboard Key from this mapping.
        /// </summary>
        /// <param name="keyboardKey">The key to remove.</param>
        public void RemoveInput(Keys keyboardKey)
        {
            mKeys.Remove(keyboardKey);
        }

        /// <summary>
        /// Adds a GamePad Button from this mapping.
        /// </summary>
        /// <param name="gamePadButton">The button to remove.</param>
        public void RemoveInput(GamePadButtons gamePadButton)
        {
            mGamePadButtons.Remove(gamePadButton);
        }

        /// <summary>
        /// Removes a Mouse Button from this mapping.
        /// </summary>
        /// <param name="mouseButton">The button to add.</param>
        public void RemoveInput(MouseButtons mouseButton)
        {
            mMouseButtons.Remove(mouseButton);
        }
    }
}
